/* 
 *      BaseLexer.java
 *
 *      Copyright 2008 Pablo Nicolas Diaz Bilotto <pablonicolas.diaz@gmail.com>
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */
package lexer;

import java.io.IOException;
import java.io.LineNumberReader;
import java.io.Reader;

import lexer.token.Token;
import errorService.IErrorReporter;



/**
 * The Class BaseLexer.
 * @param <TraductOut> 
 * @param <StateType> 
 */
public abstract class BaseLexer<TraductOut, StateType> {

	/** The Source. */
	private LineNumberReader Source;

	/** The reporter. */
	private IErrorReporter reporter;

	/** The tsymbol. */
	private TraductOut tsymbol = null;

	/** The symbol. */
	private int symbol = 0;

	/** The Sym advance. */
	private boolean SymAdvance = true;

	/**
	 * Instantiates a new base lexer.
	 * 
	 * @param ReaderX the reader x
	 * @param R the r
	 */
	public BaseLexer(Reader ReaderX, IErrorReporter R) {
		this.setReporter(R);
		this.Source = new LineNumberReader(ReaderX);
		Source.setLineNumber(1);
	}

	/**
	 * Action.
	 * 
	 * @param symbol the symbol
	 * @param tr_sym the tr_sym
	 * @param state the state
	 * @param lineNumber the line number
	 */
	protected abstract void Action(int symbol, TraductOut tr_sym,
			StateType state, int lineNumber);

	/**
	 * Advance stream.
	 * 
	 * @param symbol the symbol
	 * @param s the s
	 * 
	 * @return true, if successful
	 */
	protected abstract boolean advanceStream(TraductOut symbol, StateType s);

	/**
	 * Close source.
	 */
	public void CloseSource() {
		try {
			this.Source.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Gets the initial state.
	 * 
	 * @return the state type
	 */
	protected abstract StateType GetInitialState();

	/**
	 * Gets the new state.
	 * 
	 * @param symbol the symbol
	 * @param state the state
	 * 
	 * @return the new state
	 */
	protected abstract StateType getNewState(TraductOut symbol, StateType state);

	/**
	 * Gets the reporter.
	 * 
	 * @return the reporter
	 */
	public IErrorReporter getReporter() {
		return reporter;
	}

	/**
	 * Gets the token.
	 * 
	 * @return the token
	 * 
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public synchronized Token getToken() throws IOException {
		StateType state = this.GetInitialState();
		do {
			if (SymAdvance) {
				symbol = Source.read();
				tsymbol = traduct(symbol);
			}
			Action(symbol, tsymbol, state, Source.getLineNumber());
			SymAdvance = advanceStream(tsymbol, state);
			state = getNewState(tsymbol, state);
		} while (!isEndState(state));
		return internalGetToken();
	}

	/**
	 * Internal get token.
	 * 
	 * @return the token
	 */
	protected abstract Token internalGetToken();

	/**
	 * Checks if is end state.
	 * 
	 * @param state the state
	 * 
	 * @return true, if is end state
	 */
	protected abstract boolean isEndState(StateType state);

	/**
	 * Sets the reporter.
	 * 
	 * @param reporter the new reporter
	 */
	protected void setReporter(IErrorReporter reporter) {
		this.reporter = reporter;
	}

	/**
	 * Traduct.
	 * 
	 * @param symbol the symbol
	 * 
	 * @return the traduct out
	 */
	protected abstract TraductOut traduct(int symbol);

}